/**
 * HTTP 通信服务
 * 提供封装的网络请求功能，统一处理错误和响应
 */

const AppConfig = require('../config/app.config');
const logger = require('../utils/logger').logger;

// 默认请求配置
const DEFAULT_OPTIONS = {
  timeout: AppConfig.API.TIMEOUT,
  dataType: 'json',
  responseType: 'text'
};

// 错误代码映射
const ERROR_CODES = {
  // 请求错误
  REQUEST_ERROR: 1000,
  // 网络错误
  NETWORK_ERROR: 1001,
  // 超时错误
  TIMEOUT_ERROR: 1002,
  // 服务器错误
  SERVER_ERROR: 1003,
  // 认证错误
  AUTH_ERROR: 1004,
  // 业务错误
  BUSINESS_ERROR: 1005
};

/**
 * 生成完整的请求URL
 * @param {string} url - 请求路径
 * @returns {string} 完整的请求URL
 */
function generateUrl(url) {
  // 如果是完整URL，直接返回
  if (url.startsWith('http://') || url.startsWith('https://')) {
    return url;
  }
  
  // 否则，与基础URL拼接
  return `${AppConfig.API.BASE_URL}${url.startsWith('/') ? url : '/' + url}`;
}

/**
 * 格式化请求参数
 * @param {Object} data - 请求参数
 * @returns {Object} 格式化后的请求参数
 */
function formatRequestData(data) {
  if (!data || typeof data !== 'object') {
    return data;
  }
  
  // 移除undefined值
  const formattedData = {};
  Object.keys(data).forEach(key => {
    if (data[key] !== undefined) {
      formattedData[key] = data[key];
    }
  });
  
  return formattedData;
}

/**
 * 处理成功响应
 * @param {Object} response - 响应对象
 * @param {Function} resolve - Promise 成功回调
 * @param {Function} reject - Promise 失败回调
 */
function handleSuccess(response, resolve, reject) {
  // 检查响应状态码
  const statusCode = response.statusCode;
  
  // 状态码为200-299范围内视为成功
  if (statusCode >= 200 && statusCode < 300) {
    resolve(response.data);
    return;
  }
  
  // 处理特定状态码
  switch (statusCode) {
    case 401:
      // 处理身份验证错误
      handleAuthError(response, reject);
      break;
    case 403:
      // 处理授权错误
      reject({
        errorCode: ERROR_CODES.AUTH_ERROR,
        errorMsg: '没有权限访问该资源',
        statusCode,
        data: response.data
      });
      break;
    case 404:
      // 处理资源不存在错误
      reject({
        errorCode: ERROR_CODES.SERVER_ERROR,
        errorMsg: '请求的资源不存在',
        statusCode,
        data: response.data
      });
      break;
    case 500:
    case 502:
    case 503:
      // 处理服务器错误
      reject({
        errorCode: ERROR_CODES.SERVER_ERROR,
        errorMsg: '服务器错误',
        statusCode,
        data: response.data
      });
      break;
    default:
      // 处理其他错误
      reject({
        errorCode: ERROR_CODES.BUSINESS_ERROR,
        errorMsg: '请求失败',
        statusCode,
        data: response.data
      });
  }
}

/**
 * 处理身份验证错误
 * @param {Object} response - 响应对象
 * @param {Function} reject - Promise 失败回调
 */
function handleAuthError(response, reject) {
  // 可以在这里处理登录过期的情况，例如清除本地 token 并跳转到登录页面
  // const app = getApp();
  // if (app && typeof app.logout === 'function') {
  //   app.logout();
  // }
  
  reject({
    errorCode: ERROR_CODES.AUTH_ERROR,
    errorMsg: '登录已过期，请重新登录',
    statusCode: response.statusCode,
    data: response.data
  });
}

/**
 * 处理失败响应
 * @param {Object} error - 错误对象
 * @param {Function} reject - Promise 失败回调
 */
function handleFail(error, reject) {
  logger.error('请求失败', error);
  
  // 判断错误类型
  if (error.errMsg) {
    if (error.errMsg.includes('timeout')) {
      // 处理超时错误
      reject({
        errorCode: ERROR_CODES.TIMEOUT_ERROR,
        errorMsg: '请求超时，请检查网络连接',
        error
      });
    } else if (error.errMsg.includes('fail')) {
      // 处理网络错误
      reject({
        errorCode: ERROR_CODES.NETWORK_ERROR,
        errorMsg: '网络异常，请检查网络连接',
        error
      });
    } else {
      // 处理其他错误
      reject({
        errorCode: ERROR_CODES.REQUEST_ERROR,
        errorMsg: '请求失败',
        error
      });
    }
  } else {
    // 处理其他错误
    reject({
      errorCode: ERROR_CODES.REQUEST_ERROR,
      errorMsg: '请求失败',
      error
    });
  }
}

/**
 * 创建HTTP请求
 * @param {Object} options - 请求选项
 * @returns {Promise} Promise对象
 */
function request(options) {
  // 合并默认选项
  const requestOptions = { ...DEFAULT_OPTIONS, ...options };
  
  // 生成完整URL
  const url = generateUrl(requestOptions.url);
  
  // 格式化请求数据
  if (requestOptions.data) {
    requestOptions.data = formatRequestData(requestOptions.data);
  }
  
  // 设置请求头
  const header = requestOptions.header || {};
  
  // 如果 header 中没有 content-type，且方法不是 GET，则设置默认值
  if (!header['content-type'] && requestOptions.method && requestOptions.method.toUpperCase() !== 'GET') {
    header['content-type'] = 'application/json';
  }
  
  // 记录请求日志
  logger.debug('发起请求', {
    url,
    method: requestOptions.method,
    data: requestOptions.data
  });
  
  return new Promise((resolve, reject) => {
    wx.request({
      url,
      data: requestOptions.data,
      header,
      method: requestOptions.method,
      dataType: requestOptions.dataType,
      responseType: requestOptions.responseType,
      timeout: requestOptions.timeout,
      success: (response) => {
        logger.debug('请求成功', {
          url,
          statusCode: response.statusCode,
          data: response.data
        });
        
        handleSuccess(response, resolve, reject);
      },
      fail: (error) => {
        logger.error('请求失败', {
          url,
          error
        });
        
        handleFail(error, reject);
      }
    });
  });
}

/**
 * 发起GET请求
 * @param {string} url - 请求URL
 * @param {Object} data - 请求参数
 * @param {Object} options - 其他选项
 * @returns {Promise} Promise对象
 */
function get(url, data = {}, options = {}) {
  return request({
    url,
    data,
    method: 'GET',
    ...options
  });
}

/**
 * 发起POST请求
 * @param {string} url - 请求URL
 * @param {Object} data - 请求参数
 * @param {Object} options - 其他选项
 * @returns {Promise} Promise对象
 */
function post(url, data = {}, options = {}) {
  return request({
    url,
    data,
    method: 'POST',
    ...options
  });
}

/**
 * 发起PUT请求
 * @param {string} url - 请求URL
 * @param {Object} data - 请求参数
 * @param {Object} options - 其他选项
 * @returns {Promise} Promise对象
 */
function put(url, data = {}, options = {}) {
  return request({
    url,
    data,
    method: 'PUT',
    ...options
  });
}

/**
 * 发起DELETE请求
 * @param {string} url - 请求URL
 * @param {Object} data - 请求参数
 * @param {Object} options - 其他选项
 * @returns {Promise} Promise对象
 */
function del(url, data = {}, options = {}) {
  return request({
    url,
    data,
    method: 'DELETE',
    ...options
  });
}

/**
 * 上传文件
 * @param {string} url - 请求URL
 * @param {string} filePath - 文件路径
 * @param {string} name - 文件对应的key
 * @param {Object} formData - 附加的表单数据
 * @param {Object} options - 其他选项
 * @returns {Promise} Promise对象
 */
function uploadFile(url, filePath, name, formData = {}, options = {}) {
  // 生成完整URL
  const fullUrl = generateUrl(url);
  
  // 记录上传请求日志
  logger.debug('发起文件上传', {
    url: fullUrl,
    filePath,
    name,
    formData
  });
  
  return new Promise((resolve, reject) => {
    const uploadTask = wx.uploadFile({
      url: fullUrl,
      filePath,
      name,
      formData,
      header: options.header,
      timeout: options.timeout || DEFAULT_OPTIONS.timeout,
      success: (response) => {
        logger.debug('文件上传成功', {
          url: fullUrl,
          statusCode: response.statusCode
        });
        
        // 处理响应数据
        try {
          const data = JSON.parse(response.data);
          handleSuccess({ statusCode: response.statusCode, data }, resolve, reject);
        } catch (error) {
          handleSuccess({ statusCode: response.statusCode, data: response.data }, resolve, reject);
        }
      },
      fail: (error) => {
        logger.error('文件上传失败', {
          url: fullUrl,
          error
        });
        
        handleFail(error, reject);
      }
    });
    
    // 返回上传任务，以便外部可以监听上传进度
    resolve(uploadTask);
  });
}

// 导出模块
module.exports = {
  request,
  get,
  post,
  put,
  del,
  uploadFile,
  ERROR_CODES
}; 